#include <stdint.h>
#include <string.h>

/* HAL */
#include "app_timer.h"
#include "boards.h"
#include "simple_hal.h"

/* Core */
#include "access_config.h"
#include "device_state_manager.h"
#include "mesh_stack.h"
#include "nrf_mesh.h"
#include "nrf_mesh_config_core.h"
#include "nrf_mesh_configure.h"
#include "nrf_mesh_events.h"
#include "nrf_mesh_gatt.h"
#include "proxy.h"

/* Provisioning and configuration */
#include "mesh_app_utils.h"
#include "mesh_provisionee.h"

/* Models */
#include "command_server.h"
#include "command_common.h"
#include "model_config_file.h"

/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"

/* Example specific includes */
// #include "app_config.h"
#include "example_common.h"
// #include "nrf_mesh_config_examples.h"
// #include "light_switch_example_common.h"
// #include "app_onoff.h"
#include "ble_softdevice_support.h"

/*****************************************************************************
 * Definitions
 *****************************************************************************/
#define ONOFF_SERVER_0_LED (11)
#define APP_ONOFF_ELEMENT_INDEX (0)

/*****************************************************************************
 * Forward declaration of static functions
 *****************************************************************************/
static void mesh_events_handle(const nrf_mesh_evt_t* p_evt);
static command_msg_status_t app_onoff_server_set_cb(const command_server_t* p_server, command_msg_set_t set_msg);
static command_msg_data_t app_onoff_server_get_cb(const command_server_t* p_server);

/*****************************************************************************
 * Static variables
 *****************************************************************************/
static bool                   m_device_provisioned;
static nrf_mesh_evt_handler_t m_event_handler = {
    .evt_cb = mesh_events_handle,
};

static command_server_t m_onoff_server = {.get_cb = app_onoff_server_get_cb, .set_cb = app_onoff_server_set_cb};

/* 设置请求回调 */
static command_msg_status_t app_onoff_server_set_cb(const command_server_t* p_server, command_msg_set_t msg)
{
    /* Resolve the server instance here if required, this example uses only 1 instance. */

    bool onoff = msg.data[0];

    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting GPIO value: %d\n", !onoff);

    hal_led_pin_set(ONOFF_SERVER_0_LED, !onoff);

    command_msg_status_t status_msg;
    status_msg.data[0] = onoff;

    return status_msg;
}

/* 读取请求回调 */
static command_msg_data_t app_onoff_server_get_cb(const command_server_t* p_server)
{
    /* Resolve the server instance here if required, this example uses only 1 instance. */
    command_msg_data_t data_msg;
    data_msg.data[0] = !hal_led_pin_get(ONOFF_SERVER_0_LED);
    return data_msg;
}

// 初始化model的回调
static void app_model_init(void)
{
    ERROR_CHECK(command_server_init(&m_onoff_server, APP_ONOFF_ELEMENT_INDEX, COMMAND_SERVER_LIGHT));

    ERROR_CHECK(access_model_subscription_list_alloc(m_onoff_server.model_handle));
}

/*************************************************************************************************/

// mesh事件回调
static void mesh_events_handle(const nrf_mesh_evt_t* p_evt)
{
    if (p_evt->type == NRF_MESH_EVT_ENABLED) {
        // mesh启用时读取灯状态。
        // APP_ERROR_CHECK(app_onoff_value_restore(&m_onoff_server_0));
    }
}

// 清除配置
static void node_reset(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
    model_config_file_clear();
    hal_led_blink_ms(HAL_LED_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
    /* This function may return if there are ongoing flash operations. */
    mesh_stack_device_reset();
}

// 配置器回调
static void config_server_evt_cb(const config_server_evt_t* p_evt)
{
    if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET) {
        node_reset();
    }
}

#if NRF_MESH_LOG_ENABLE
static const char m_usage_string[] = "\n"
                                     "\t\t-------------------------------------------------------------------------------\n"
                                     "\t\t Button/RTT 1) LED state will toggle and inform clients about the state change.\n"
                                     "\t\t-------------------------------------------------------------------------------\n";
#endif

// 按钮回调
static void button_event_handler(uint32_t button_number)
{
    /* Increase button number because the buttons on the board is marked with 1 to 4 */
    button_number++;
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
    switch (button_number) {
        /* 按下按钮1切换灯状态，并主动推送状态到客户端 */
        case 1: {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "User action \n");
            hal_led_pin_set(ONOFF_SERVER_0_LED, !hal_led_pin_get(ONOFF_SERVER_0_LED));
            // ERROR_CHECK(command_server_status_publish(&m_onoff_server, hal_led_pin_get(ONOFF_SERVER_0_LED)));
            break;
        }

        default:
            // 打印帮助信息
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
            break;
    }
}

// rtt输入
static void app_rtt_input_handler(int key)
{
    if (key >= '1' && key <= '4') {
        uint32_t button_number = key - '1';
        button_event_handler(button_number);
    }
    else {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
    }
}

// 打印单播地址
static void unicast_address_print(void)
{
    dsm_local_unicast_address_t node_address;
    dsm_local_unicast_addresses_get(&node_address);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start);
}

// 配置成功回调
static void provisioning_complete_cb(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n");

    unicast_address_print();
}

// 初始化models的回调
static void models_init_cb(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
    app_model_init();
}

static void mesh_init(void)
{
    /* Initialize the application storage for models */
    model_config_file_init();

    mesh_stack_init_params_t init_params = {.core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
                                            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
                                            .core.p_uuid             = NULL,
                                            .models.models_init_cb   = models_init_cb,
                                            .models.config_server_cb = config_server_evt_cb};

    // 初始化mesh栈，并判断是否配网
    uint32_t status = mesh_stack_init(&init_params, &m_device_provisioned);

    if (status == NRF_SUCCESS) {
        /* 检查应用程序存储的数据是否有效，如果无效则清除所有数据并使用默认值。 */
        status = model_config_file_config_apply();
    }

    switch (status) {
        // 如果存储的数据无效，清除所有数据并使用默认值
        case NRF_ERROR_INVALID_DATA:
            /* Clear model config file as loading failed */
            model_config_file_clear();
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Data in the persistent memory was corrupted. Device starts as unprovisioned.\n");
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Reboot device before starting of the provisioning process.\n");
            break;
        case NRF_SUCCESS:
            break;
        default:
            ERROR_CHECK(status);
    }
}

static void initialize(void)
{
    // 初始化日志
    __LOG_INIT(LOG_SRC_APP | LOG_SRC_FRIEND, LOG_LEVEL_DBG1, LOG_CALLBACK_DEFAULT);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Server Demo -----\n");

    // 初始化计时器
    ERROR_CHECK(app_timer_init());

    // 初始化LED
    hal_leds_init();

    // 初始化ble栈
    ble_stack_init();

    // 初始化mesh
    mesh_init();
}

static void start(void)
{
    rtt_input_enable(app_rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);

    // 配网设置
    if (!m_device_provisioned) {
        // 静态OBB
        static const uint8_t            static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA;
        mesh_provisionee_start_params_t prov_start_params                   = {.p_static_data                       = static_auth_data,
                                                             .prov_sd_ble_opt_set_cb              = NULL,
                                                             .prov_complete_cb                    = provisioning_complete_cb,
                                                             .prov_device_identification_start_cb = NULL,
                                                             .prov_device_identification_stop_cb  = NULL,
                                                             .prov_abort_cb                       = NULL,
                                                             .p_device_uri                        = EX_URI_LS_SERVER};
        ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params));
    }
    else {
        // 打印单播地址
        unicast_address_print();
    }

    mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get());

    /* NRF_MESH_EVT_ENABLED is triggered in the mesh IRQ context after the stack is fully enabled.
     * This event is used to call Model APIs for establishing bindings and publish a model state information. */
    nrf_mesh_evt_handler_add(&m_event_handler);
    ERROR_CHECK(mesh_stack_start());

    // 打印帮助信息
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
}

int main(void)
{
    initialize();
    start();

    for (;;) {
        (void)sd_app_evt_wait();
    }
}
